package com.fhsk.file.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ReUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fhsk.file.business.entity.bo.attachment.AttachmentBo;
import com.fhsk.file.business.entity.bo.attachment.AttachmentConditionBo;
import com.fhsk.file.business.entity.bo.user.UserConditionBo;
import com.fhsk.file.business.entity.dto.attachment.AttachmentDto;
import com.fhsk.file.business.entity.dto.user.UserDto;
import com.fhsk.file.business.entity.vo.attachment.AttachmentVo;
import com.fhsk.file.business.entity.vo.user.UserVo;
import com.fhsk.file.business.mapper.AttachmentMapper;
import com.fhsk.file.business.mapper.UserMapper;
import com.fhsk.file.business.service.IAttachmentService;
import com.fhsk.file.business.service.IUserService;
import com.fhsk.file.common.constants.Constants;
import com.fhsk.file.common.enums.ChangePicEnum;
import com.fhsk.file.common.enums.ClarityEnum;
import com.fhsk.file.common.enums.ResourceTypeEnum;
import com.fhsk.file.common.enums.WatermarkEnum;
import com.fhsk.file.common.utils.file.PdfUtil;
import com.fhsk.file.common.utils.file.WatermarkUtil;
import com.fhsk.file.common.vo.AjaxResult;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 附件表接口实现类
 */
@Slf4j
@Service
public class AttachmentServiceImpl extends ServiceImpl<AttachmentMapper, AttachmentDto> implements IAttachmentService {

    @Resource
    private AttachmentMapper attachmentMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private IUserService userService;

    @Value("${filepath.windows}")
    private String windowsPath;

    @Value("${filepath.linux}")
    private String linuxPath;

    @Override
    public Map<String, Object> getAttachmentListByCondition(AttachmentConditionBo conditionBo) {
        List<AttachmentVo> list = Lists.newArrayList();
        long count = 0L;

        if (0 == conditionBo.getLimit()) {
            //limit为0，则不分页（查询全部）
            list = baseMapper.getAttachmentListByCondition(conditionBo);
            count = list.size();
        } else {
            //分页查询
            PageHelper.startPage(conditionBo.getPage(), conditionBo.getLimit(), conditionBo.getOrderBy());
            List<AttachmentVo> attachmentVos = baseMapper.getAttachmentListByCondition(conditionBo);

            PageInfo<AttachmentVo> pageInfo = new PageInfo<>(attachmentVos);
            list = pageInfo.getList();
            count = pageInfo.getTotal();
        }

        // 获取创建人
        List<String> userOids = list.stream().map(t -> t.getCreateBy()).distinct().collect(Collectors.toList());
        Map<String, UserVo> userVoMap = null;
        if (CollectionUtil.isNotEmpty(userOids)) {
            UserConditionBo condition = new UserConditionBo();
            condition.setUserOids(userOids);
            List<UserVo> userVos = userMapper.getList(condition);
            if (CollectionUtil.isNotEmpty(userVos)) {
                userVoMap = userVos.stream().collect(Collectors.toMap(e -> e.getOid(), e -> e, (k1, k2) -> k1));
            }
        }

        for (AttachmentVo attachmentVo : list) {
//            attachmentVo.setWebUrl(webPrefix + attachmentVo.getFileOid());
            if (null != userVoMap) {
                UserVo userVo = userVoMap.get(attachmentVo.getCreateBy());
                attachmentVo.setCreateName(null == userVo ? null : userVo.getRealName());
            }
        }

        Map<String, Object> map = new HashMap<>(4);
        map.put("list", list);
        map.put("count", count);
        return map;
    }

    @Override
    public AjaxResult addAttachment(AttachmentBo attachmentBo) {
        AttachmentDto attachment = new AttachmentDto();
        BeanUtil.copyProperties(attachmentBo, attachment);
        if (save(attachment)) {
            return AjaxResult.success("保存成功");
        } else {
            return AjaxResult.fail("保存失败");
        }
    }

    @Override
    public AjaxResult updateAttachment(AttachmentBo attachmentBo) {
        AttachmentDto attachment = new AttachmentDto();
        BeanUtil.copyProperties(attachmentBo, attachment);
        if (updateById(attachment)) {
            return AjaxResult.success("保存成功");
        } else {
            return AjaxResult.fail("保存失败");
        }
    }

    @Override
    public AttachmentVo getDetail(String fileOid) {
        AttachmentConditionBo condition = new AttachmentConditionBo();
        condition.setFileOid(fileOid);
        List<AttachmentVo> list = attachmentMapper.getAttachmentListByCondition(condition);
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }

        AttachmentVo attachmentVo = list.get(0);
//        attachmentVo.setWebUrl(webPrefix + attachmentVo.getFileOid());

        // 获取创建人
        if (StringUtils.isNotBlank(attachmentVo.getCreateBy())) {
            LambdaQueryWrapper<UserDto> lqw = new LambdaQueryWrapper<>();
            lqw.eq(UserDto::getOid, attachmentVo.getCreateBy());
            UserDto userDto = userMapper.selectOne(lqw);
            if (null != userDto) {
                attachmentVo.setCreateName(userDto.getRealName());
            }
        }

        return attachmentVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult upload(MultipartFile file, MultipartFile img, AttachmentBo attachmentBo) throws Exception {
        if (null == file) {
            return AjaxResult.fail("文件不能为空");
        }

        //原始文件名
        String originalName = file.getOriginalFilename();
        originalName = ReUtil.replaceAll(originalName, Constants.FILE_NAME_RE, "");
        //获取文件格式
        String fileExtName = Objects.requireNonNull(FileUtil.extName(originalName)).toLowerCase();
        // 格式校验
        if (StringUtils.isBlank(fileExtName) || !"pdf".equals(fileExtName)) {
            return AjaxResult.fail("文件格式错误");
        }

        // 获取文件的大小 KB
        long fileSize = file.getSize() / 1024;
        if (fileSize > 300 * 1024) {
            return AjaxResult.fail("文件大小不能超过300MB");
        }

        if (null == attachmentBo) {
            return AjaxResult.fail("上传信息不能为空");
        }

        if (!WatermarkEnum.NO.getCode().equals(attachmentBo.getIsWatermark())) {
            // 加水印
            if (null == WatermarkEnum.getWatermarkByCode(attachmentBo.getIsWatermark())) {
                return AjaxResult.fail("水印类型不正确");
            }

            if (WatermarkEnum.PICTURE.getCode().equals(attachmentBo.getIsWatermark())) {
                // 图片水印
                if (null == img) {
                    return AjaxResult.fail("水印图片不能为空");
                }
                // 水印大小,kb
                long imgSize = img.getSize() / 1024;
                if (imgSize > 300) {
                    return AjaxResult.fail("水印图片大小不能超过300KB");
                }
            } else {
                // 文字水印
                if (StringUtils.isBlank(attachmentBo.getWatermarkText())) {
                    return AjaxResult.fail("水印文字不能为空");
                }
            }
        }

        if (ChangePicEnum.YES.getCode().equals(attachmentBo.getIsChangePic())) {
            // 转图片
            if (null == ClarityEnum.getClarityByCode(attachmentBo.getClarity())) {
                return AjaxResult.fail("清晰度不正确");
            }
        }

//        try {
//            InputStream inputStream = new ByteArrayInputStream(file.getBytes());
//            //原始文件名
//            String originalName = file.getOriginalFilename();
//            originalName = ReUtil.replaceAll(originalName, Constants.FILE_NAME_RE, "");
//            //获取文件格式
//            String fileExtName = Objects.requireNonNull(FileUtil.extName(originalName)).toLowerCase();
//            // 格式校验
//            if (StringUtils.isBlank(fileExtName) || !"pdf".equals(fileExtName)) {
//                return AjaxResult.fail("文件格式错误");
//            }
//            String config = redisComponent.hgetObjectValue(RedisKeyEnum.CONFIG_KEY.getValue(), SystemConstants.CHECK_CONTENT_FILE_TYPE, SystemConstants.CONFIG_VALUE);
//            String isCheckType = redisComponent.hgetObjectValue(RedisKeyEnum.CONFIG_KEY.getValue(), SystemConstants.CHECK_FILE_TYPE_STRICT, SystemConstants.CONFIG_VALUE);
//            String checkSizeParam = redisComponent.hgetObjectValue(RedisKeyEnum.CONFIG_KEY.getValue(), SystemConstants.CHECK_FILE_CONTENT_SIZE, SystemConstants.CONFIG_VALUE);
//            Long checkSize = StringUtils.isEmpty(checkSizeParam) ? 50 * 1024 * 1024 : Long.valueOf(checkSizeParam) * 1024 * 1024;
//            if (!FileTypeUtil.isFileRealTypeMatch(inputStream, originalName, file.getSize(), fileExtName, config)
//                    && (!StringUtils.isEmpty(isCheckType)) && SystemConstants.TRUE.equals(isCheckType)) {
//                return AjaxResult.fail(MessageConstants.WRONG_FILE_TYPE);
//            }
//            if (FileTypeUtil.fileHasXSSContent(inputStream, originalName, file.getSize(), config, checkSize)) {
//                return AjaxResult.fail(MessageConstants.WRONG_FILE_CONTENT);
//            }
//            //获取文件的大小
//            Long fileSize = file.getSize() / 1024;

        long start = System.currentTimeMillis();
        log.error("处理开始：" + com.fhsk.file.common.utils.DateUtil.formatDatetime(new Date()));

        //新的文件名
        String uuidName = IdUtil.simpleUUID() + "." + fileExtName;
        //文件相对路径，例如：/20221015/pdf/
        String relativeDir = getRelativeDir(fileExtName);
        //文件基础路径，例如：D:\file\20221015\pdf\
        String baseDir = (isWindows() ? windowsPath : linuxPath) + relativeDir;
        //检查是否存在该目录
        File fileDir = new File(baseDir);
        if (!fileDir.exists()) {
            fileDir.mkdirs();
        }
        // 文件存放路径，例如：D:\file\20221015\pdf\2ad26e33d9564aebbd2a26f5fcdfc37f.pdf
        String tempFilePath = baseDir + "temp" + uuidName;
        String filePath = baseDir + uuidName;
        String fileRelativePath = relativeDir + uuidName;
        String fileOid = IdUtil.simpleUUID();
        //生成pdf预览路径
        //String previewPath = isDoc(fileExtName) || isPpt(fileExtName) ? fileRelativePath.replace("." + fileExtName, ".pdf") : fileRelativePath;
        AttachmentDto attachment = new AttachmentDto()
                .setOriginalName(originalName)
                .setNewName(uuidName)
                .setFileOid(fileOid)
                .setFileExtName(fileExtName)
                .setFileSize(fileSize)
                .setFilePath(fileRelativePath)
                .setFileType(getFileType(fileExtName))
                .setPreviewPath(fileRelativePath)
                .setIsWatermark(attachmentBo.getIsWatermark())
//                    .setWatermarkType(attachmentBo.getWatermarkType())
                .setWatermarkText(attachmentBo.getWatermarkText())
                .setIsChangePic(attachmentBo.getIsChangePic())
                .setClarity(attachmentBo.getClarity())
                .setOpacity(attachmentBo.getOpacity())
                .setFontColor(attachmentBo.getFontColor())
                .setCreateBy(userService.getCurrentUser().getOid())
                .setCreateTime(new Date());

        // 资源文件存入数据库
        boolean save = save(attachment);
        if (save) {
            byte[] bytes = null;
            if (ChangePicEnum.YES.getCode().equals(attachmentBo.getIsChangePic())) {
                // 转图片
                // 清晰度转换
                float scale = 2.0F;
                if (ClarityEnum.LOW.getCode().equals(attachmentBo.getClarity())) {
                    scale = 2.0F;
                } else if (ClarityEnum.MIDDLE.getCode().equals(attachmentBo.getClarity())) {
                    scale = 3.0F;
                } else if (ClarityEnum.HIGH.getCode().equals(attachmentBo.getClarity())) {
                    scale = 4.0F;
                }

                if (WatermarkEnum.PICTURE.getCode().equals(attachmentBo.getIsWatermark())) {
                    // 加图片背景
                    if (null != img) {
                        ByteArrayOutputStream byteArrayOutputStream = WatermarkUtil.pdfAddWaterMark(file, img);
                        bytes = PdfUtil.pdf2png(byteArrayOutputStream.toByteArray(), Constants.PIC_TYPE, scale);
                    }
                } else if (WatermarkEnum.TEXT.getCode().equals(attachmentBo.getIsWatermark())
                        || WatermarkEnum.SIMPLE.getCode().equals(attachmentBo.getIsWatermark())
                        || WatermarkEnum.LOWER_RIGHT.getCode().equals(attachmentBo.getIsWatermark())) {
                    // 加文字水印
                    if (StringUtils.isNotBlank(attachmentBo.getWatermarkText())) {
                        ByteArrayOutputStream byteArrayOutputStream = WatermarkUtil.pdfAddWaterMarkText(file, attachmentBo.getWatermarkText(),
                                attachmentBo.getIsWatermark(), attachmentBo.getOpacity(), attachmentBo.getFontColor());
                        bytes = PdfUtil.pdf2png(byteArrayOutputStream.toByteArray(), Constants.PIC_TYPE, scale);
                    }
                } else {
                    // 无水印
                    bytes = PdfUtil.pdf2png(file.getBytes(), Constants.PIC_TYPE, scale);
                }

            } else {
                // 不转图片
                if (WatermarkEnum.PICTURE.getCode().equals(attachmentBo.getIsWatermark())) {
                    // 图片水印
                    if (null != img) {
                        ByteArrayOutputStream byteArrayOutputStream = WatermarkUtil.pdfAddWaterMark(file, img);
                        bytes = byteArrayOutputStream.toByteArray();
                    }
                } else if (WatermarkEnum.TEXT.getCode().equals(attachmentBo.getIsWatermark())
                        || WatermarkEnum.SIMPLE.getCode().equals(attachmentBo.getIsWatermark())
                        || WatermarkEnum.LOWER_RIGHT.getCode().equals(attachmentBo.getIsWatermark())) {
                    // 加文字水印
                    if (StringUtils.isNotBlank(attachmentBo.getWatermarkText())) {
                        ByteArrayOutputStream byteArrayOutputStream = WatermarkUtil.pdfAddWaterMarkText(file, attachmentBo.getWatermarkText(),
                                attachmentBo.getIsWatermark(), attachmentBo.getOpacity(), attachmentBo.getFontColor());
                        bytes = byteArrayOutputStream.toByteArray();
                    }
                } else {
                    // 无水印
                    bytes = file.getBytes();
                }
            }

            // 保存文件大小 KB
            if (null != bytes) {
                long fileSizeConvert = bytes.length / 1024;
                AttachmentDto upAttachmentDto = new AttachmentDto();
                upAttachmentDto.setId(attachment.getId());
                upAttachmentDto.setFileSizeConvert(fileSizeConvert);
                upAttachmentDto.setUpdateBy(userService.getCurrentUser().getOid());
                upAttachmentDto.setUpdateTime(new Date());

                updateById(upAttachmentDto);
            }

            BufferedOutputStream outputStream = null;
            try {
                outputStream = FileUtil.getOutputStream(filePath);
                outputStream.write(bytes);
            } catch (Exception e) {
                throw new Exception("文件上传失败");
            } finally {
                IoUtil.close(outputStream);
            }

        }

        AttachmentVo vo = BeanUtil.toBean(attachment, AttachmentVo.class);
        // 文件请求地址
//        vo.setWebUrl(webPrefix + vo.getFileOid());

        log.error("处理结束：" + com.fhsk.file.common.utils.DateUtil.formatDatetime(new Date()) + "，用时：" + (System.currentTimeMillis() - start));

        return AjaxResult.success(vo);
//        } catch (Exception e) {
//            log.error("文件上传出错{}", e.getMessage());
//        }
//        return AjaxResult.fail("上传失败请重试");
    }

    /**
     * 获取服务器文件基础路径
     *
     * @param fileExtName
     * @return 文件基础路径，列如：/20221015/pdf/
     */
    private String getRelativeDir(String fileExtName) {
        String now = DateUtil.format(DateUtil.date(), "yyyyMMdd");
        String type = getFileType(fileExtName);
        return File.separator + now + File.separator + type + File.separator;
    }

    /**
     * 获取文件类型
     *
     * @param extName
     * @return
     */
    private String getFileType(String extName) {
//        List<DictionaryDataDto> list = dictionaryDataService.list((new LambdaQueryWrapper<DictionaryDataDto>())
//                .eq(DictionaryDataDto::getDictValue, extName)
//                .eq(DictionaryDataDto::getDictLabel, extName));
//        if (!CollectionUtil.isEmpty(list)) {
//            return list.get(0).getDictType();
//        } else {
//            return "other";
//        }
        return ResourceTypeEnum.PDF.getName();
    }

    /**
     * 判断服务器是linux还是windows
     *
     * @return 是否是windows系统
     * @author luojian
     */
    private boolean isWindows() {
        return System.getProperties().getProperty("os.name").toLowerCase().contains("windows");
    }
}